﻿using System;
using System.IO;

namespace Gmantis.Imaging
{
    public static class GifCodec
    {
        // Fields
        internal static byte[] Signature = new byte[] { 0x47, 0x49, 70 };

        // Methods
        public static Bitmap Decode(Stream stream)
        {
            Bitmap bmp = new Bitmap();
            Decode(bmp, stream);
            return bmp;
        }

        internal static void Decode(Bitmap bmp, Stream stream)
        {
            try
            {
                bmp.BeginUpdate();
                DecodeInternal(bmp, stream);
            }
            finally
            {
                bmp.EndUpdate();
            }
        }

        private static void DecodeInternal(Bitmap bmp, Stream stream)
        {
            BinaryReader br = new BinaryReader(stream);
            if (!Bitmap.Match(br.ReadBytes(3), Signature))
            {
                throw new BadImageFormatException("GIF signature not found!");
            }
            br.ReadBytes(3);
            GifInfo gif = new GifInfo(br);
            bmp.Frames.Clear();
            bool flag = false;
            while (!flag && (stream.Position < stream.Length))
            {
                Separator separator2 = (Separator)br.ReadByte();
                if (separator2 != Separator.Extension)
                {
                    if (separator2 != Separator.Image)
                    {
                        if (separator2 != Separator.EndOfFile)
                        {
                            throw new BadImageFormatException("Unknown block type.");
                        }
                        goto Label_011F;
                    }
                    if (bmp.Frames.Count == 0)
                    {
                        gif.ReadImageData(br, bmp);
                        bmp.Frames.Add(new AnimationFrame(gif, bmp));
                    }
                    else
                    {
                        Bitmap bitmap = new Bitmap();
                        gif.ReadImageData(br, bitmap);
                        bmp.Frames.Add(new AnimationFrame(gif, bitmap));
                    }
                    continue;
                }
                switch (((Extension)br.ReadByte()))
                {
                    case Extension.Comment:
                        {
                            gif.ReadCommentExtension(br);
                            continue;
                        }
                    case Extension.Application:
                        {
                            gif.ReadApplicationExtension(br);
                            continue;
                        }
                    case Extension.GraphicsControl:
                        {
                            gif.ReadGraphicsControlExtension(br);
                            continue;
                        }
                    case Extension.PlainText:
                        {
                            gif.ReadPlainTextExtension(br);
                            continue;
                        }
                    default:
                        throw new BadImageFormatException("Unknown extension.");
                }
            Label_011F:
                flag = true;
            }
            if (bmp != null)
            {
                bmp.Frames.LoopCount = (gif.LoopFlag == 0) ? 0 : ((gif.LoopCount > 0) ? gif.LoopCount : 0x7fffffff);
            }
        }

        // Nested Types
        internal enum Extension
        {
            Application = 0xff,
            Comment = 0xfe,
            GraphicsControl = 0xf9,
            PlainText = 1
        }

        internal enum Separator
        {
            EndOfFile = 0x3b,
            Extension = 0x21,
            Image = 0x2c
        }
    }
}
